#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std;
#include "parser.h"

int tokenPointer = 0;
int programCountre = 0;
string actualToken;
vector<string> tokenList;
vector<_stackvariable> stackvariables;
int variableAddressPointer = 1;
bool rightValue = false;
int leftValuePointer = 0;
vector<string> byteCodeVector;
string operatorType;
int programCounter = 0;

void actual_token_is() //Check next token
{
	if (symboltable[lexemeArray[tokenPointer]].token[0]==100) 
		actualToken="Q";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==101)
		actualToken="void";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==102)
		actualToken="int";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==103)
		actualToken=";";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==104)
		actualToken="{";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==105)
	   actualToken="}";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==106)
		actualToken="(";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==107)
		actualToken=")";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==108)
		actualToken="+";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==109)
		actualToken="-";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==110)
		actualToken="*";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==111)
		actualToken="/";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==112)
		actualToken="%";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==113)
		actualToken="&&";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==114)
		actualToken="||";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==115)
		actualToken="!=";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==116)
		actualToken="==";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==117)
		actualToken="=";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==118)
		actualToken="<=";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==119)
		actualToken=">=";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==120)
		actualToken=">";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==121)
		actualToken="<";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==123)
		actualToken=",";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==124)
		actualToken="if";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==125)
		actualToken="else";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==126)
		actualToken="while";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==127)
		actualToken="input";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==99)
		actualToken="output";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==19)
		actualToken="identifier";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==21)
		actualToken="number";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==122)
		actualToken="return";
	else if (symboltable[lexemeArray[tokenPointer]].token[0]==98)
		actualToken="$";
}

bool next_token_is_in(vector<string>& tokenList)
{
	for (int i=0; i<(int)tokenList.size(); i++)
	{
		if (actualToken.compare(tokenList[i]) == 0)
		{
			tokenList.clear();
			return true;
		}
	}
	tokenList.clear();
	return false;
}

void program(int niveau)
{
	actual_token_is();
	printf_niveau(niveau, "program");
	tokenList.push_back(";");
	if(next_next_next_token_is_in(tokenList))
	{
		variable_declaration_statement_list(niveau+1);
		function_declaration_list(niveau+1);
	}
	tokenList.push_back("(");
	if(next_next_next_token_is_in(tokenList))
	{
		function_declaration_list(niveau+1);
	}
	else
	{
		error();
	}
}
void variable_declaration_statement_list(int niveau)
{
	printf_niveau(niveau, "variable_declaration_statement_list");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	if(next_token_is_in(tokenList)) //Follow set for variable_declaration_statement
	{
		variable_declaration_statement(niveau+1);
		rest_variable_declaration_statement_list(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_variable_declaration_statement_list(int niveau)
{
	printf_niveau(niveau, "rest_variable_declaration_statement_list");
	tokenList.push_back(";");
	if(next_next_next_token_is_in(tokenList)) //to distinguish between variables and function calls
	{
		tokenList.push_back("int");
		tokenList.push_back("Q");
		if(next_token_is_in(tokenList)) //First set for variable_declaration_statement_list
		{
			variable_declaration_statement_list(niveau+1);
		}
	}
	else
	{
		tokenList.push_back("(");
		if(next_next_next_token_is_in(tokenList))
		{
			tokenList.push_back("int");
			tokenList.push_back("Q");
			tokenList.push_back("void");
			if(next_token_is_in(tokenList)){}//die (follow set af rest_variable_declaration_statement_list
		}
		else
		{
			error();
		}
	}
}
 
void variable_declaration_statement(int niveau)
{
	printf_niveau(niveau, "variable_declaration_statement");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	if(next_token_is_in(tokenList))
	{
		variable_declaration(niveau+1);
		match(niveau+1, ";"); //terminal
	}
	else
	{
		error();
	}
}

void variable_declaration(int niveau)
{
	printf_niveau(niveau, "variable_declaration");
	tokenList.push_back("Q");
	tokenList.push_back("int");
	if(next_token_is_in(tokenList))
	{
		type(niveau+1);
		match(niveau+1, "identifier"); //terminal
		_stackvariable tempVariable;
		tempVariable.name = symboltable[lexemeArray[tokenPointer-1]].lexture;
		tempVariable.offset = variableAddressPointer;
		variableAddressPointer++;
		stackvariables.push_back(tempVariable);
	}
	else
	{
		error();
	}
}

void type(int niveau)
{
	printf_niveau(niveau, "type");
	tokenList.push_back("int");
	if(next_token_is_in(tokenList)) //terminal
	{
		match(niveau+1, "int");
	}
	else
	{
		tokenList.push_back("Q");
		if(next_token_is_in(tokenList))
		{
			Q(niveau+1);
		}
		else
		{
			error();
		}
	}
}

void Q(int niveau)
{
	printf_niveau(niveau, "Q");
	tokenList.push_back("Q");
	if(next_token_is_in(tokenList)) //terminal
	{
		match(niveau+1, "Q");
	}
	else
	{
		error();
	}
}
			
void function_declaration_list(int niveau)
{
	printf_niveau(niveau, "function_declaration_list");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	tokenList.push_back("void");
	if(next_token_is_in(tokenList))
	{
		function_declaration(niveau+1);
		rest_function_declaration_list(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_function_declaration_list(int niveau)
{ 
	printf_niveau(niveau, "rest_function_declaration_list");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	tokenList.push_back("void");
	if(next_token_is_in(tokenList))
	{
		function_declaration_list(niveau+1);
	}
	else
	{
		tokenList.push_back("$"); // If end of file
		if(next_token_is_in(tokenList))
		{
			match(niveau, "$");
		}
		
		else
		{
			error();
		}
	}
}

void function_declaration(int niveau)
{ 
	printf_niveau(niveau, "function_declaration");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	tokenList.push_back("void");
	if (next_token_is_in(tokenList))
	{
		result_type(niveau+1);
		function_identifier(niveau+1);
		match(niveau+1, "("); //terminal
		formal_parameter_list(niveau+1);
		match(niveau+1, ")"); //terminal
		block(niveau+1);
	}
	else
	{
		error()	;
	}
}

void result_type(int niveau)
{
	printf_niveau(niveau, "result_type");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	if (next_token_is_in(tokenList))
	{
		type(niveau+1);
	}
	else
	{
		tokenList.push_back("void");
		if (next_token_is_in(tokenList))
		{
			match(niveau+1, "void");
		}
		else
		{
			error();
		}
	}
}

void function_identifier(int niveau)
{
	printf_niveau(niveau, "function_identifier");
	match(niveau+1, "identifier");
}

void formal_parameter_list(int niveau)
{
	printf_niveau(niveau, "formal_parameter_list");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	if (next_token_is_in(tokenList))
	{
		variable_declaration_list(niveau+1);
	}
	else
	{
		tokenList.push_back("void");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "void");
		}
		else
		{
			error();
		}
	}
}

void variable_declaration_list(int niveau)
{
	printf_niveau(niveau, "variable_declaration_list");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	if(next_token_is_in(tokenList))
	{
		variable_declaration(niveau+1);
		rest_variable_declaration_list(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_variable_declaration_list(int niveau)
{
	printf_niveau(niveau, "rest_variable_declaration_list");
	tokenList.push_back(",");
	if (next_token_is_in(tokenList))
	{
		match(niveau+1, ",");
		variable_declaration_list(niveau+1);
	}
	else
	{
		tokenList.push_back(")");
		if(next_token_is_in(tokenList)){} //die - follow set
		else
		{
    		error();
		}
	}
}

void block(int niveau)
{
	printf_niveau(niveau, "block");
	tokenList.push_back("{");
	if (next_token_is_in(tokenList))
	{
		match(niveau+1, "{");
		statement_list(niveau+1);
		match(niveau+1, "}");
	}
	else
	{
		error();
	}
}

void statement_list(int niveau)
{
	printf_niveau(niveau, "statement_list");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("if");
	tokenList.push_back("while");
	tokenList.push_back("return");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	
	if (next_token_is_in(tokenList))
	{
		statement(niveau+1);
		rest_statement_list(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_statement_list(int niveau)
{
	printf_niveau(niveau, "rest_statement_list");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("if");
	tokenList.push_back("while");
	tokenList.push_back("return");
	tokenList.push_back("int");
	tokenList.push_back("Q");
	
	if (next_token_is_in(tokenList))
	{
		statement_list(niveau+1);
	}
	else
	{
		tokenList.push_back("}");
		if(next_token_is_in(tokenList)){} //die - follow set
		else
		{
			error();
		}
	}
}

void statement(int niveau)
{
	printf_niveau(niveau, "statement");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	if(next_token_is_in(tokenList))
	{
		tokenList.push_back("=");
		if(next_next_token_is_in(tokenList))
		{
			assignment_statement(niveau+1);
		}
		else
		{
			tokenList.push_back("(");
			if(next_next_token_is_in(tokenList))
			{
				function_call(niveau+1);
				match(niveau+1, ";");
			}
			else
			{
				error();
			}
		}
	}
	else
	{
		tokenList.push_back("if");
		if (next_token_is_in(tokenList))
		{
			conditional_statement(niveau+1);
		}
		else
		{
			tokenList.push_back("while");
			if (next_token_is_in(tokenList))
			{
			while_loop(niveau+1);
			}
			else
			{
				tokenList.push_back("return");
				if (next_token_is_in(tokenList))
				{
					match(niveau+1, "return");
					expression(niveau+1);
					match(niveau+1, ";"); 
				}
				else
				{
					tokenList.push_back("int");
					tokenList.push_back("Q");
					if (next_token_is_in(tokenList))
					{
						variable_declaration_statement(niveau+1);
					}
					else
					{
						error();
					}
				}
			}
		}
	}
}

void assignment_statement(int niveau)
{
	printf_niveau(niveau,  "assignment_statement");		
	tokenList.push_back("identifier");		
	tokenList.push_back("input");		
	tokenList.push_back("output");
	if (next_token_is_in(tokenList))
	{
		rightValue = false;
		variable(niveau+1);
		match(niveau+1, "=");  // terminal
		expression(niveau+1);
		match(niveau+1, ";"); // terminal
		
		stringstream temp;
		temp.str("");
		temp << "istore " << leftValuePointer;
		byteCodeVector.push_back(temp.str()); //emit
		programCounter++;
	}
}

void conditional_statement(int niveau)
{
	printf_niveau(niveau, "conditional_statement");
	tokenList.push_back("if");
	if (next_token_is_in(tokenList))
	{
		match(niveau+1, "if"); // terminal
		match(niveau+1, "("); // terminal
		expression(niveau+1);
		match(niveau+1, ")"); // terminal

		// Placeholder for ifeq instruction. (How many instructions are there in if-block?)
		byteCodeVector.push_back("");
		int instructionPlaceholder = programCounter;
		programCounter++;
		
		block(niveau+1); // Execute block instructions

		stringstream temp;
		temp << "ifeq " << programCounter-instructionPlaceholder+1; // How many instructions until else-statement? +1 is because of goto statement.
		byteCodeVector[instructionPlaceholder]=temp.str();		

		// Placeholder for goto instruction. (How many instructions are there in else block?)
		byteCodeVector.push_back(""); 
	    instructionPlaceholder = programCounter;
		programCounter++;
		
		elsepart(niveau+1);

		temp.str("");
		temp << "goto " << programCounter-instructionPlaceholder;
		byteCodeVector[instructionPlaceholder]=temp.str();		

	}
	else
	{
		error();
	}
}

void elsepart(int niveau)
{
	printf_niveau(niveau, "elsepart");		
	tokenList.push_back("else");
	if (next_token_is_in(tokenList))
	{
		match(niveau+1, "else"); // terminal
		block(niveau+1);
	}
	else
	{
		tokenList.push_back("identifier");		
		tokenList.push_back("input");		
		tokenList.push_back("output");		
		tokenList.push_back("if");		
		tokenList.push_back("while");		
		tokenList.push_back("return ");		
		tokenList.push_back("int");		
		tokenList.push_back("Q");		
		tokenList.push_back("}");
		if(next_token_is_in(tokenList)){} //die - follow set
		else
		{
			error();
		}
	}
}

void while_loop(int niveau)
{
	printf_niveau(niveau, "while_loop");
	tokenList.push_back("while");
	if (next_token_is_in(tokenList))
	{
		match(niveau+1, "while"); // terminal
		match(niveau+1, "("); // terminal
		expression(niveau+1);
		match(niveau+1, ")"); //terminal
		block(niveau+1);
	}
	else
	{
		error();
	}
}

void expression(int niveau)
{
	printf_niveau(niveau, "expression");		
	tokenList.push_back("-");		
	tokenList.push_back("!");		
	tokenList.push_back("(");		
	tokenList.push_back("identifier");		
	tokenList.push_back("input");		
	tokenList.push_back("output");		
	tokenList.push_back("number");
	if (next_token_is_in(tokenList))
	{
		logical_and_expression(niveau+1);
		rest_expression(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_expression(int niveau)
{
	printf_niveau(niveau, "rest_expression");		
	tokenList.push_back("||");
	if (next_token_is_in(tokenList))
	{
		match(niveau+1, "||");
		logical_and_expression(niveau+1);
		rest_expression(niveau+1);
	}	
	else
	{
		tokenList.push_back(";");
		tokenList.push_back(")");
		tokenList.push_back(",");
		if(next_token_is_in(tokenList)){} //die - follow set for rest_expression
		else
		{
			error();
		}
	}
}

void logical_and_expression(int niveau)
{
	printf_niveau(niveau, "logical_and_expression");
	tokenList.push_back("-");
	tokenList.push_back("!");
	tokenList.push_back("(");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("number");
	if (next_token_is_in(tokenList))
	{
		equality_expression(niveau+1);
		rest_logical_and_expression(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_logical_and_expression(int niveau)
{
	printf_niveau(niveau, "rest_logical_and_expression");
	tokenList.push_back("&&");
	if (next_token_is_in(tokenList))
	{
		match(niveau+1, "&&");
		equality_expression(niveau+1);
		rest_logical_and_expression(niveau+1);
	}
	else
	{
		tokenList.push_back(",");
		tokenList.push_back(";");
		tokenList.push_back(")");
		if(next_token_is_in(tokenList)){} //die - follow set for rest_logical_and_expression
		else
		{
			error();
		}
	}
}

void equality_expression(int niveau)
{
	printf_niveau(niveau, "equality_expression");
	tokenList.push_back("-");
	tokenList.push_back("!");
	tokenList.push_back("(");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("number");
	if (next_token_is_in(tokenList))
	{
		relation_expression(niveau+1);
		rest_equality_expression(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_equality_expression(int niveau)
{
	printf_niveau(niveau, "rest_equality_expression");
	tokenList.push_back("==");
	tokenList.push_back("!=");
	if (next_token_is_in(tokenList))
	{
		equality_operator(niveau+1);
		relation_expression(niveau+1);
		rest_equality_expression(niveau+1);
	}
	else
	{
		tokenList.push_back("&&");
		tokenList.push_back(",");
		tokenList.push_back(";");
		tokenList.push_back(")");
		if(next_token_is_in(tokenList)){} //die - follow set for rest_equality_expression
		else
		{
			error();
		}
	}
}

void relation_expression(int niveau)
{
	printf_niveau(niveau, "relation_expression");
	tokenList.push_back("-");
	tokenList.push_back("!");
	tokenList.push_back("(");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("number");
	if(next_token_is_in(tokenList))
	{
		arithmetic_expression(niveau+1);
		rest_relation_expression(niveau+1);
	}
	else
	{
		error();
	}
}
void rest_relation_expression(int niveau)
{
	printf_niveau(niveau, "rest_relation_expression");
	tokenList.push_back("<");
	tokenList.push_back("<=");
	tokenList.push_back(">=");
	tokenList.push_back(">");
	if(next_token_is_in(tokenList))
	{
		relation_operator(niveau+1);
		arithmetic_expression(niveau+1);
		if(operatorType.compare("<")==0)
		{
			stringstream temp;
			temp << "isub";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;
			
			temp.str("");
			temp << "iflt 3"; // If less than; go 3 instructions forward
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;

			temp.str("");
			temp << "bipush 0";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;

			temp.str("");
			temp << "goto 2";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;

			temp.str("");
			temp << "bipush 1";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;
		}
		if(operatorType.compare(">=")==0)
		{
			stringstream temp;
			temp << "isub";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;
			
			temp.str("");
			temp << "iflt 3"; // If less than; go 3 instructions forward
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;

			temp.str("");
			temp << "bipush 1";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;

			temp.str("");
			temp << "goto 2";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;

			temp.str("");
			temp << "bipush 0";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;
		}
		rest_relation_expression(niveau+1);
	}
	else
	{
		tokenList.push_back("==");
		tokenList.push_back("!=");
		tokenList.push_back("&&");
		tokenList.push_back(",");
		tokenList.push_back(";");
		tokenList.push_back(")");
		if(next_token_is_in(tokenList)){} //die - follow set for rest_relational_expression
		else
		{
			error();
		}
	}
}

void arithmetic_expression(int niveau)
{
	printf_niveau(niveau, "arithmetic_expression");
	tokenList.push_back("-");
	tokenList.push_back("!");
	tokenList.push_back("(");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("number");
	if(next_token_is_in(tokenList))
	{
		term_expression(niveau+1);
		rest_arithmetic_expression(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_arithmetic_expression(int niveau)
{
	printf_niveau(niveau, "rest_arithmetic_expression");
	tokenList.push_back("+");
	tokenList.push_back("-");
	if(next_token_is_in(tokenList))
	{
		arithmetic_operator(niveau+1);
		term_expression(niveau+1);
		if (operatorType.compare("+")==0)
		{
			stringstream temp;
			temp << "iadd";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;
		}
		else if (operatorType.compare("-")==0)
		{
			stringstream temp;
			temp << "isub";
			byteCodeVector.push_back(temp.str()); //emit
			programCounter++;
		}
		rest_arithmetic_expression(niveau+1);
	}
	else
	{
		tokenList.push_back("<");
		tokenList.push_back("<=");
		tokenList.push_back(">=");
		tokenList.push_back(">");
		tokenList.push_back("!=");
		tokenList.push_back("==");
		tokenList.push_back("&&");
		tokenList.push_back(",");
		tokenList.push_back(";");
		tokenList.push_back(")");
		if(next_token_is_in(tokenList)){} //die - follow set for rest_arithmetic_expression
		else
		{
			error();
		}
	}
}

void term_expression(int niveau)
{
	printf_niveau(niveau, "term_expression");
	tokenList.push_back("-");
	tokenList.push_back("!");
	tokenList.push_back("(");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("number");
	if(next_token_is_in(tokenList))
	{
		unary_expression(niveau+1);
		rest_term_expression(niveau+1);
	}
}

void rest_term_expression(int niveau)
{
	printf_niveau(niveau, "rest_term_expression");
	tokenList.push_back("*");
	tokenList.push_back("/");
	tokenList.push_back("%");
	if(next_token_is_in(tokenList))
	{
		term_operator(niveau+1);
		unary_expression(niveau+1);
		rest_term_expression(niveau+1);
	}
	else
	{
		tokenList.push_back("+");
		tokenList.push_back("-");
		tokenList.push_back("<");
		tokenList.push_back("<=");
		tokenList.push_back(">=");
		tokenList.push_back(">");
		tokenList.push_back("!=");
		tokenList.push_back("==");
		tokenList.push_back("&&");
		tokenList.push_back(",");
		tokenList.push_back(";");
		tokenList.push_back(")");
		if(next_token_is_in(tokenList)){} //die - follow set
		else
		{
			error();
		}
	}
}

void unary_expression(int niveau)
{
	printf_niveau(niveau, "unary_expression");
	tokenList.push_back("-");
	tokenList.push_back("!");
	if(next_token_is_in(tokenList))
	{
		unary_operator(niveau+1);
		unary_expression(niveau+1);
	}
	else
	{
		tokenList.push_back("(");
		tokenList.push_back("identifier");
		tokenList.push_back("input");
		tokenList.push_back("output");
		tokenList.push_back("number");
		if(next_token_is_in(tokenList))
		{
			factor(niveau+1);
		}
		else
		{
			error();
		}
	}
}

void factor(int niveau)
{
	printf_niveau(niveau, "factor");
	tokenList.push_back("(");
	if(next_token_is_in(tokenList))
	{
		match(niveau+1, "(");
		expression(niveau+1);
		match(niveau+1, ")");
	}
	else
	{
		tokenList.push_back("number");
		if(next_token_is_in(tokenList))
		{
			constant(niveau+1);
		}
		else
		{				
			tokenList.push_back("identifier");
			tokenList.push_back("input");
			tokenList.push_back("output");
			if (next_token_is_in(tokenList))
			{
				tokenList.push_back("=");
				if(next_next_token_is_in(tokenList)) // to distinguish between variable and function call
				{
					variable(niveau+1);
				}
				else
				{
					tokenList.push_back("(");
					if(next_next_token_is_in(tokenList))
					{
						function_call(niveau+1);
					}
					else
					{
						rightValue = true;
						variable(niveau+1);
					}
				}
			}
			else
			{
				error();
			}
		}
	}
}

void function_call(int niveau)
{
	printf_niveau(niveau, "function_call");
	tokenList.push_back("identifier");
	if(next_token_is_in(tokenList))
	{
		function_identifier(niveau+1);
		match(niveau+1, "(");
		actual_parameter_list(niveau+1);
		match(niveau+1, ")");
	}
	else
	{
		error();
	}
}
void actual_parameter_list(int niveau)
{
	printf_niveau(niveau, "actual_parameter_list");
	tokenList.push_back("-");
	tokenList.push_back("!");
	tokenList.push_back("(");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("number");
	if(next_token_is_in(tokenList))
	{
		expression_list(niveau+1);
	}
	else
	{
		tokenList.push_back("void");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "void");
		}
		else
		{
			error();
		}
	}
}

void expression_list(int niveau)
{
	printf_niveau(niveau, "expression_list");
	tokenList.push_back("-");
	tokenList.push_back("!");
	tokenList.push_back("(");
	tokenList.push_back("identifier");
	tokenList.push_back("input");
	tokenList.push_back("output");
	tokenList.push_back("number");
	if(next_token_is_in(tokenList))
	{
		expression(niveau+1);
		rest_expression_list(niveau+1);
	}
	else
	{
		error();
	}
}

void rest_expression_list(int niveau)
{
	printf_niveau(niveau, "rest_expression_list");	tokenList.push_back("-");
	tokenList.push_back(",");
	if(next_token_is_in(tokenList))
	{
		match(niveau+1, ",");
		expression_list(niveau+1);
	}
	else
	{
		tokenList.push_back(")");
		if(next_token_is_in(tokenList)){} //die - follow set
		else
		{
			error();
		}
	}
}

void variable(int niveau)
{
	printf_niveau(niveau, "variable");	
	tokenList.push_back("identifier");
	if(next_token_is_in(tokenList))
	{
		simple_variable(niveau+1);
	}
	else
	{
		tokenList.push_back("input");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "input");
		}
		else
		{
			tokenList.push_back("output");
			if(next_token_is_in(tokenList))
			{
				match(niveau+1, "output");
			}
			else
			{
				error();
			}
		}
	}
}

void simple_variable(int niveau)
{
	printf_niveau(niveau, "simple_variable");
	match(niveau+1, "identifier");
	if(rightValue == false)
	{
		for(int i=0; i < (int)stackvariables.size() ; i++)
		{
			if(stackvariables[i].name.compare(symboltable[lexemeArray[tokenPointer-1]].lexture)==0)
			{
				leftValuePointer = stackvariables[i].offset;
			}
		}
	}
	else
	{
		for(int i=0; i < (int)stackvariables.size() ; i++)
		{
			if(stackvariables[i].name.compare(symboltable[lexemeArray[tokenPointer-1]].lexture)==0)
			{
				stringstream temp;
				temp << "iload " << i+1;
				byteCodeVector.push_back(temp.str()); //emit
				programCounter++;
			}
		}
	}
}

void constant(int niveau)
{
	printf_niveau(niveau, "constant");
	match(niveau+1, "number");

	stringstream temp;
	temp << "bipush " << symboltable[lexemeArray[tokenPointer-1]].value;
	byteCodeVector.push_back(temp.str()); //emit
	programCounter++;
}

void equality_operator(int niveau)
{
	printf_niveau(niveau, "equality_operator");	
	tokenList.push_back("==");
	if(next_token_is_in(tokenList))
	{
		match(niveau+1, "==");
	}
	else
	{
		tokenList.push_back("!=");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "!=");
		}
		else
		{
			error();
		}
	}
}

void relation_operator(int niveau)
{	
	printf_niveau(niveau, "relation_operator");
	tokenList.push_back("<");
	if(next_token_is_in(tokenList))
	{
		match(niveau+1, "<");
		operatorType="<";
	}
	else
	{
		tokenList.push_back("<=");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "<=");
		}
		else
		{
			tokenList.push_back(">=");
			if(next_token_is_in(tokenList))
			{
				match(niveau+1, ">=");
				operatorType=">=";
			}
			else
			{
				tokenList.push_back(">");
				if(next_token_is_in(tokenList))
				{
					match(niveau+1, ">");
				}
				else
				{
					error();
				}
			}
		}
	}
}

void arithmetic_operator(int niveau)
{
	printf_niveau(niveau, "arithmetic_operator");
	tokenList.push_back("+");
	if(next_token_is_in(tokenList))
	{
		match(niveau+1, "+");
		operatorType="+";
	}
	else
	{
		tokenList.push_back("-");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "-");
			operatorType="-";
		}
		else
		{
			error();
		}
	}
}

void term_operator(int niveau)
{
	printf_niveau(niveau, "term_operator");
	tokenList.push_back("*");
	if(next_token_is_in(tokenList))
	{
		match(niveau+1, "*");
	}
	else
	{
		tokenList.push_back("/");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "/");
		}
		else
		{
			tokenList.push_back("%");
			if(next_token_is_in(tokenList))
			{
				match(niveau+1, "%");
			}
			else
			{
				error();
			}
		}
	}
}

void unary_operator(int niveau)
{
	printf_niveau(niveau, "unary_operator");
	tokenList.push_back("-");
	if(next_token_is_in(tokenList))
	{
		match(niveau+1, "-");
	}
	else
	{
		tokenList.push_back("!");
		if(next_token_is_in(tokenList))
		{
			match(niveau+1, "!");
		}
		else
		{
			error();
		}
	}
}

bool next_next_token_is_in(vector<string>& tokenList)
{
	string temp_actualToken;

	if (symboltable[lexemeArray[tokenPointer+1]].token[0]==106)
		temp_actualToken="(";
	else if (symboltable[lexemeArray[tokenPointer+1]].token[0]==117)
		temp_actualToken="=";
	else
		temp_actualToken="other";
	for (int i=0; i<(int)tokenList.size(); i++)
	{
		if (temp_actualToken.compare(tokenList[i]) == 0)
		{
			tokenList.clear();
			return true;
		}
	}
	tokenList.clear();
	return false;
}

bool next_next_next_token_is_in(vector<string>& tokenList)
{
	string temp_actualToken;

	if (symboltable[lexemeArray[tokenPointer+2]].token[0]==103)
		temp_actualToken=";";
	else if (symboltable[lexemeArray[tokenPointer+2]].token[0]==106)
		temp_actualToken="(";
	else
		temp_actualToken="other";
	for (int i=0; i<(int)tokenList.size(); i++)
	{
		if (temp_actualToken.compare(tokenList[i]) == 0)
		{
			tokenList.clear();
			return true;
		}
	}
	tokenList.clear();
	return false;
}

void match(int niveau, string str)
{
	if(str.compare(actualToken)==0)
	{
		int i;
		for(i = 0 ; i < niveau ; i++)
		{
			cout << ".";
		}
		cout << str;
		if (actualToken.compare("identifier")==0 || actualToken.compare("number")==0)
			cout << " " << symboltable[lexemeArray[tokenPointer]].lexture;
		cout << endl;
		
		if (actualToken.compare("$") ==0)
		{
			cout << "Success!" << endl;
			cout << "" << endl;
			//for(int i=0; i<(int)stackvariables.size();i++)
				//cout << stackvariables[i].name << endl;
			emit();
			exit(EXIT_SUCCESS);

		}
		
		if ((int)lexemeArray.size() > tokenPointer + 1)
		{
			tokenPointer++;
			actual_token_is();
		}
	}
	else
		error();
}

void printf_niveau(int niveau, string str)
{
	int i;
	for(i = 0 ; i < niveau ; i++)
	{
		cout << ".";
	}
	cout << "<" << str << ">" << endl;
}

void error(void)
{
	printf("Error\n");
	exit(EXIT_FAILURE);
}

void emit(void)
{
	for(int i=0; i < (int)byteCodeVector.size() ; i++)
	{
		cout << byteCodeVector[i] << endl;
	}
}